package vip.liux.contracts.models.identity;

import jakarta.persistence.EntityNotFoundException;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import vip.liux.contracts.repositories.identity.IdentityRoleRepository;
import vip.liux.contracts.security.core.IRoleValidator;
import vip.liux.contracts.security.core.extensions.ILookupNormalizer;
import vip.liux.contracts.security.core.extensions.IdentityError;
import vip.liux.contracts.security.core.extensions.IdentityErrorDescriber;
import vip.liux.contracts.security.core.extensions.IdentityResult;

import java.util.ArrayList;
import java.util.List;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * 角色领域管理器
 * <p>用于管理角色的创建、更新、删除等操作。</p>
 */
@Component
public class RoleDomainManager {
    private static final Logger logger = getLogger(RoleDomainManager.class);

    /**
     * 角色存储库
     */
    @Getter
    private final IdentityRoleRepository roleRepo;

    /**
     * 角色验证器列表
     */
    @Getter
    private final List<IRoleValidator> validators = new ArrayList<>();

    /**
     * 错误描述器
     */
    @Getter
    @Setter
    private IdentityErrorDescriber describer;

    /**
     * 键值标准化器
     */
    @Getter
    @Setter
    private ILookupNormalizer keyNormalizer;

    /**
     * 构造方法
     *
     * @param roleRepo 角色存储库
     */
    public RoleDomainManager(IdentityRoleRepository roleRepo) {
        this.roleRepo = roleRepo;
    }

    /**
     * 创建角色
     *
     * @param role 角色对象
     * @return 创建结果
     */
    public IdentityResult createRole(IdentityRole role) {
        Assert.notNull(role, "Role must not be null");
        IdentityResult result = validateRoleAsync(role);
        if (!result.isSucceeded()) {
            return result;
        }
        updateNormalizedRoleName(role);
        roleRepo.save(role);
        return IdentityResult.success();
    }

    /**
     * 更新角色的标准化名称
     *
     * @param role 角色对象
     */
    public void updateNormalizedRoleName(IdentityRole role) {
        String name = getRoleName(role);
        roleRepo.setNormalizedRoleName(role, normalizeKey(name));
    }

    /**
     * 更新角色信息
     *
     * @param role 角色对象
     * @return 更新结果
     */
    public IdentityResult update(IdentityRole role) {
        IdentityResult result = validateRoleAsync(role);
        if (!result.isSucceeded()) {
            return result;
        }
        updateNormalizedRoleName(role);
        roleRepo.save(role);
        return IdentityResult.success();
    }

    /**
     * 删除角色
     *
     * @param role 角色对象
     * @return 删除结果
     */
    public IdentityResult delete(IdentityRole role) {
        Assert.notNull(role, "Role must not be null");
        roleRepo.delete(role);
        return IdentityResult.success();
    }

    /**
     * 检查角色是否存在
     *
     * @param roleName 角色名称
     * @return 如果存在返回 true，否则返回 false
     */
    public boolean exitsRole(String roleName) {
        return roleRepo.findByNameOrNormalizedName(roleName).isEmpty();
    }

    /**
     * 标准化键值
     *
     * @param key 键值
     * @return 标准化后的键值
     */
    public String normalizeKey(String key) {
        return keyNormalizer != null ? keyNormalizer.normalizeName(key) : key;
    }

    /**
     * 根据 ID 查找角色
     *
     * @param id 角色 ID
     * @return 角色对象
     */
    public IdentityRole findById(Long id) {
        return roleRepo.findById(id).orElse(null);
    }

    /**
     * 获取角色名称
     *
     * @param role 角色对象
     * @return 角色名称
     */
    public String getRoleName(IdentityRole role) {
        return roleRepo.getRoleName(role);
    }

    /**
     * 设置角色名称
     *
     * @param role     角色对象
     * @param roleName 角色名称
     * @return 设置结果
     */
    public IdentityResult setRoleName(IdentityRole role, String roleName) {
        roleRepo.setRoleName(role, roleName);
        updateNormalizedRoleName(role);
        return IdentityResult.success();
    }

    /**
     * 获取角色 ID
     *
     * @param role 角色对象
     * @return 角色 ID
     */
    public String getRoleId(IdentityRole role) {
        return roleRepo.getRoleId(role);
    }

    /**
     * 根据角色名称查找角色
     *
     * @param roleName 角色名称
     * @return 角色对象
     */
    public IdentityRole findByRoleName(String roleName) {
        return roleRepo.findByNameOrNormalizedName(normalizeKey(roleName))
                .orElseThrow(() -> new EntityNotFoundException("Role not found: " + roleName));
    }

    /**
     * 验证角色
     *
     * @param role 角色对象
     * @return 验证结果
     */
    protected IdentityResult validateRoleAsync(IdentityRole role) {
        List<IdentityError> errors = new ArrayList<>();
        for (IRoleValidator validator : validators) {
            IdentityResult validationResult = validator.validate(this, role);
            if (!validationResult.isSucceeded()) {
                errors.addAll(validationResult.getErrors());
            }
        }
        if (!errors.isEmpty()) {
            logger.warn("Role {} validation failed: {}", getRoleId(role), String.join(",", errors.stream().map(IdentityError::code).toList()));
            return IdentityResult.failed(errors);
        }
        return IdentityResult.success();
    }
}